import type { ReactNode } from 'react';
import { Link } from 'react-router-dom-v5-compat';
import lowerCase from 'lodash/lowerCase';
import capitalize from 'lodash/capitalize';

import { vulnerabilitiesPlatformPath, vulnerabilitiesUserWorkloadsPath } from 'routePaths';

import CollapsibleCard from 'Components/CollapsibleCard';
import type {
    Container,
    ContainerImage,
    ContainerResources,
    ContainerVolume,
    Deployment,
    EmbeddedSecret,
} from 'types/deployment.proto';
import KeyValuePairs from './KeyValuePairs';

const containerConfigMap = {
    command: { label: 'Commands' },
    args: { label: 'Arguments' },
    ports: { label: 'Ports' },
    volumes: { label: 'Volumes' },
    secrets: { label: 'Secrets' },
};

const getContainerConfigurations = (container: Container) => {
    if (!container.config) {
        return null;
    }
    // @ts-expect-error TODO: ports, volumes, and secrets are typed on the top level Container, not the ContainerConfig
    // TODO: Do we need to update the proto file or the code here?
    const { command, args, ports, volumes, secrets } = container.config;
    return { command, args, ports, volumes, secrets };
};

type ContainerImageProps = {
    image: ContainerImage;
    vulnMgmtBasePath: string;
};

function ContainerImage({ image, vulnMgmtBasePath }: ContainerImageProps) {
    const imageDetailsPageURL = `${vulnMgmtBasePath}/images/${image.id}`;

    if (!image?.name?.fullName) {
        return null;
    }
    if (image.id === '' || image.notPullable) {
        const unavailableText = image.notPullable
            ? 'image not currently pullable'
            : 'image not available until deployment is running';
        return (
            <div className="flex py-3">
                <div className="pr-1 ">Image Name:</div>
                <div className="font-500">
                    {image.name.fullName}
                    <span className="pl-1">({unavailableText})</span>{' '}
                </div>
            </div>
        );
    }
    return (
        <div className="py-3 pb-2 leading-normal border-b border-base-300">
            <div className="font-700 inline">Image Name: </div>
            <Link
                className="hover:text-primary-800 leading-normal word-break"
                to={imageDetailsPageURL}
            >
                {image.name.fullName}
            </Link>
        </div>
    );
}

type ResourcesProps = {
    resources: ContainerResources;
};

function Resources({ resources }: ResourcesProps) {
    if (!resources) {
        return <span className="py-3">None</span>;
    }
    const resourceMap = {
        cpuCoresRequest: { label: 'CPU Request (cores)' },
        cpuCoresLimit: { label: 'CPU Limit (cores)' },
        memoryMbRequest: { label: 'Memory Request (MB)' },
        memoryMbLimit: { label: 'Memory Limit (MB)' },
    };

    return <KeyValuePairs data={resources} keyValueMap={resourceMap} />;
}

type ContainerVolumesProps = {
    volumes: ContainerVolume[];
};

function ContainerVolumes({ volumes }: ContainerVolumesProps) {
    if (!volumes?.length) {
        return <span className="py-1">None</span>;
    }
    return volumes.map((volume, idx) => (
        <li
            key={volume.name}
            className={`py-2 ${idx === volumes.length - 1 ? '' : 'border-base-300 border-b'}`}
        >
            {Object.keys(volume).map((key) => {
                return volume[key] ? (
                    <div key={key} className="py-1">
                        <span className="font-700 pr-1">{capitalize(lowerCase(key))}:</span>
                        <span>{volume[key].toString()}</span>
                    </div>
                ) : null;
            })}
        </li>
    ));
}

type ContainerSecretsProps = {
    secrets: EmbeddedSecret[];
};

function ContainerSecrets({ secrets }: ContainerSecretsProps) {
    if (!secrets?.length) {
        return <span className="py-1">None</span>;
    }
    return secrets.map(({ name, path }) => (
        <div key={name} className="py-2">
            <div className="py-1">
                <span className="font-700 pr-1">Name:</span>
                <span>{name}</span>
            </div>
            <div className="py-1">
                <span className="font-700 pr-1">Container Path:</span>
                <span>{path}</span>
            </div>
        </div>
    ));
}

type ContainerConfigurationsProps = {
    deployment: Deployment;
};

function ContainerConfigurations({ deployment }: ContainerConfigurationsProps) {
    const title = 'Container configuration';
    const vulnMgmtBasePath = deployment?.platformComponent
        ? vulnerabilitiesPlatformPath
        : vulnerabilitiesUserWorkloadsPath;

    let containers: ReactNode = [];
    if (deployment.containers) {
        containers = deployment.containers.map((container: Container) => {
            const data = getContainerConfigurations(container);
            const { id, resources, volumes, secrets } = container;
            return (
                <div key={id} data-testid="deployment-container-configuration">
                    <ContainerImage image={container.image} vulnMgmtBasePath={vulnMgmtBasePath} />
                    {data && <KeyValuePairs data={data} keyValueMap={containerConfigMap} />}
                    {!!resources && !!volumes && !!secrets && (
                        <>
                            <div className="py-3 border-b border-base-300">
                                <div className="pr-1 font-700 ">Resources:</div>
                                <div className="ml-2 mt-2 w-full">
                                    <Resources resources={resources} />
                                </div>
                            </div>
                            <div className="py-3 border-b border-base-300">
                                <div className="pr-1 font-700">Volumes:</div>
                                <ul className="ml-2 mt-2 w-full">
                                    <ContainerVolumes volumes={volumes} />
                                </ul>
                            </div>
                            <div className="py-3 border-b border-base-300">
                                <div className="pr-1 font-700">Secrets:</div>
                                <div className="ml-2 mt-2 w-full">
                                    <ContainerSecrets secrets={secrets} />
                                </div>
                            </div>
                        </>
                    )}
                </div>
            );
        });
    } else {
        containers = <span className="py-1">None</span>;
    }
    return (
        <div className="px-3 pt-5">
            <CollapsibleCard title={title}>
                <div className="h-full px-3">{containers}</div>
            </CollapsibleCard>
        </div>
    );
}

export default ContainerConfigurations;
